#include "PlaceCircularPadTask.h"

#include "PadStackWidget.h"
#include "Gui.h"

#include "LeIpc7351/PadStackElement.h"
#include "LeIpc7351/Primitives/CirclePrimitive.h"

#include "LeGraphicsView/LeGraphicsItem.h"
#include "LeGraphicsView/LeGraphicsItemLayer.h"
#include "LeGraphicsView/LeGraphicsScene.h"
#include "LeGraphicsView/LeGraphicsStyle.h"
#include "LeGraphicsView/LeGraphicsPalette.h"

#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QRectF>

PlaceCircularPadTask::PlaceCircularPadTask(PadStackWidget *editor)
    : PadStackTask(editor)
    , LeGraphicsSceneEventFilter()
{
    setTile("Circular pad");
    setDescription("Place a circular pad");
    setIcon(Gui::icon("primitive-shape-circle"));
    setShortcut(QKeySequence("p,c"));
}


void PlaceCircularPadTask::start()
{
    setDiameter(0.0);
    setPosition(QPointF());
    scene()->setEventFilter(this);
    emit started(this);
}

void PlaceCircularPadTask::accept()
{
    if (m_item != nullptr)
    {
        scene()->currentLayer()->removeFromLayer(m_item);
        delete m_item;
        auto primitive = new CirclePrimitive();
        primitive->setDiameter(m_diameter);
        primitive->setPosition(m_position);
        m_element->setPrimitive(primitive);
    }
    m_item = nullptr;
    scene()->setEventFilter(nullptr);
    emit accepted(this);
}

void PlaceCircularPadTask::reject()
{
    if (m_item != nullptr)
    {
        scene()->currentLayer()->removeFromLayer(m_item);
        delete m_item;
    }
    m_item = nullptr;
    scene()->setEventFilter(nullptr);
    emit rejected(this);
}

void PlaceCircularPadTask::setPosition(QPointF position)
{
    if (m_position == position)
        return;

    m_position = position;

    if (m_item != nullptr)
        m_item->setPos(m_position);

    emit positionChanged(m_position);
}

void PlaceCircularPadTask::setDiameter(qreal diameter)
{
    if (m_diameter == diameter)
        return;

    m_diameter = diameter;

    if (m_item != nullptr)
        m_item->setDiameter(m_diameter);

    emit diameterChanged(m_diameter);
}

void PlaceCircularPadTask::drawBackground(QPainter *painter, const QRectF &rect)
{
    Q_UNUSED(painter)
    Q_UNUSED(rect)
}

void PlaceCircularPadTask::drawForeground(QPainter *painter, const QRectF &rect)
{
    Q_UNUSED(rect)

    if (m_item == nullptr)
        return;

    painter->setBrush(Qt::NoBrush);
    painter->setPen(QPen(scene()->graphicsPalette().color(LeGraphicsPalette::Highlight), 0));
    painter->drawLine(m_radiusLine);
    painter->setPen(QPen(scene()->graphicsPalette().color(LeGraphicsPalette::Highlight), 0, Qt::DotLine));
    QRectF bRect = m_item->boundingRect();
    bRect.moveCenter(m_item->pos());
    painter->drawRect(bRect);
}

bool PlaceCircularPadTask::keyPressEvent(QKeyEvent *event)
{
    Q_UNUSED(event)
    return true;
}

bool PlaceCircularPadTask::keyReleaseEvent(QKeyEvent *event)
{
    Q_UNUSED(event)
    return true;
}

bool PlaceCircularPadTask::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event)
    return true;
}

bool PlaceCircularPadTask::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    if (m_item == nullptr)
    {
        setPosition(event->scenePos());
        return true;
    }

    m_radiusLine.setP2(event->scenePos());
    setDiameter(qMax(qAbs(m_radiusLine.dx()),
                     qAbs(m_radiusLine.dy()))*2.0);
    return true;
}

bool PlaceCircularPadTask::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    if (m_item == nullptr) // First click
    {
        m_element = editor()->currentElement();
        m_item = new LeGraphicsCircleItem(GftPad);
        m_item->setPos(event->scenePos());
        scene()->currentLayer()->addToLayer(m_item);
        m_radiusLine.setP1(event->scenePos());
        return true;
    }
    // Second click
    accept();
    return true;
}

bool PlaceCircularPadTask::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
    Q_UNUSED(event)
    return true;
}

QPointF PlaceCircularPadTask::position() const
{
    return m_position;
}

qreal PlaceCircularPadTask::diameter() const
{
    return m_diameter;
}
